import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.w3c.dom.Document;

import ualrcdg.shared.CDGXMLHelper;
import ualrcdg.shared.XMLHelper;
import ualrcdg.shared.dto.Game;
import ualrcdg.shared.dto.MediaScript;
import ualrcdg.shared.dto.Page;
import ualrcdg.shared.exceptions.CDGException;
import ualrcdg.shared.exceptions.CDGParseException;
import ualrcdg.shared.requests.AuthenticatePlayerRequest;
import ualrcdg.shared.requests.FetchGameRequest;
import ualrcdg.shared.requests.GameListRequest;
import ualrcdg.shared.requests.RegisterPlayerRequest;
import ualrcdg.shared.requests.UpdateProgressRequest;
import ualrcdg.shared.requests.ValidateRuleRequest;
import ualrcdg.shared.responses.FetchGameResponse;

public class Tester
{
	static Communicator comm = null;
	static final String rootFolder = "bin\\";
	static Random r = new Random( );
	
	public static void main( String args[] ) throws CDGException, FileNotFoundException, IOException, ParserConfigurationException
	{
		//doTest( args );
		
		CDGXMLHelper.init( (new File( "cdg" ) ).toPath( ), "dtds.txt" );
		Game g = CDGXMLHelper.parseTheGame();
		MediaScript ms = g.getMediaScript( "script0" );
		String initialStateId = ms.getInitialState( );
		String initialPageId = ms.getPageId( initialStateId );
		System.out.println( ms );
		Page initialPage = g.getPage( initialPageId );
		System.out.println( initialPage );
		String transition = "button0";
		System.out.println( initialStateId + " with " + transition + " -> " + ms.getTransition( initialStateId, transition ) );
	}
	
	public static void doTest( String args[] ) throws IOException, ParserConfigurationException, CDGException, TransformerException, InterruptedException
	{
		CDGXMLHelper.init( (new File( "cdg" ) ).toPath( ), "dtds.txt" );
		
		new Thread( new Runnable()
		{
			@Override
			public void run( )
			{
				try
				{
					comm = new Communicator( );
				}
				catch( CDGException e )
				{
					e.printStackTrace();
				}
			}
		} ).start( );

		Thread.sleep( 500 );
		
		String input = null;
		BufferedReader br = new BufferedReader( new InputStreamReader( System.in ) );
		
		System.out.println( "Waiting for command..." );
		while( !( input = br.readLine( ) ).equals( "kill" ) )
		{
			if( input.equals( "/?" ) )
			{
				System.out.println( "Available commands:");
				System.out.println( " - register <username> <password>" );
				System.out.println( " - authenticate <username> <password>" );
				System.out.println( " - list" );
				System.out.println( " - fetch <gameId>" );
				System.out.println( " - validate <type> <parameters> <data>" );
				System.out.println( " - update <username> <password> <gameId> <update>" );
				continue;
			}
			
			String[] inputArgs = input.split( " " );
			
			forwardRequest( inputArgs );
			
			System.out.println( "Waiting for command..." );
		}
		
		System.out.println( "Testing complete." );
		System.exit( 0 );
	}
	
	private static ArrayList< Document > forwardRequest( String[] args ) throws CDGParseException, IOException, TransformerException
	{
		System.out.println( "makeFile(" + Arrays.toString( args ) + ")" );
		
		if( args.length < 1)
		{
			System.out.println( "Too few arguments in makeFile command [" + Arrays.toString( args ) + "]" );
			
			return null;
		}
		
		String id = Long.toHexString( r.nextLong( ) );
		
		Document req = null;
		
		switch( args[0] )
		{
			case "register":
				if( args.length != 3 )
				{
					return null;
				}
				req = CDGXMLHelper.createRegisterPlayerRequestDocument( new RegisterPlayerRequest( id, args[1], args[2] ) );
				break;
			case "authenticate":
				if( args.length != 3 )
				{
					return null;
				}
				req = CDGXMLHelper.createAuthenticatePlayerRequestDocument( new AuthenticatePlayerRequest( id, args[1], args[2] ) );
				break;
			case "list":
				if( args.length != 1 )
				{
					return null;
				}
				req = CDGXMLHelper.createGameListRequestDocument( new GameListRequest( id ) );
				break;
			case "fetch":
				if( args.length != 2 )
				{
					return null;
				}
				req = CDGXMLHelper.createFetchGameRequestDocument( new FetchGameRequest( id, args[1] ) );
				break;
			case "validate":
				if( args.length != 4 )
				{
					return null;
				}
				req = CDGXMLHelper.createValidateRuleRequestDocument( new ValidateRuleRequest( id, args[1], args[2], args[3] ) );
				break;
			case "update":
				if( args.length != 5 )
				{
					return null;
				}
				req = CDGXMLHelper.createUpdateProgressRequestDocument( new UpdateProgressRequest( id, args[1], args[2], args[3], args[4] ) );
				break;
			default:
				System.out.println( "Unable to create request with args [" + Arrays.toString( args ) + "]" );	
				break;
		}
		
		System.out.println( "Sending generated request document..." );
		System.out.println( new String( XMLHelper.writeDocumentToBytes( req ) ) );
		ArrayList< Document > responses = new ArrayList< Document >( );
		Document response = comm.sendRequest( req );
		responses.add( response );
		
		System.out.println( "Server response: " );
		System.out.println( new String( XMLHelper.writeDocumentToBytes( response ) ) );

		if( args[0].equals( "fetch" ) )
		{
			FetchGameResponse fg = CDGXMLHelper.parseFetchGameResponseDocument( response );
			for( String fileName : fg.list )
			{
				System.out.println( "Waiting for: " + fileName );
				Document file = comm.receiveFile( );
				System.out.println( "Received: " + fileName );
				System.out.println( new String( XMLHelper.writeDocumentToBytes( file ) ) );
				responses.add( file );
			}
		}
		return responses;
	}
}